/* Copyright(C) 2006-2008 Dave Sexton  *
 * http://www.codeplex.com/aip         *
 * http://www.codeplex.com/aip/license *
 ***************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Configuration.Provider;
using DaveSexton.Web.Controls.Resources;

namespace DaveSexton.Web.Controls
{
	/// <summary>
	/// An implementation of <see cref="AutoInputProtectionTextProvider"/> that generates a string of random characters, with the 
	/// option of setting predefined <see cref="CharacterSets"/> from which the provider will select at random, and a string of 
	/// characters that will never be used.  This class cannot be inherited.
	/// </summary>
	/// <remarks>
	/// <para>
	/// See the remarks in the <see cref="GenerateRandomAutoInputProtectionText"/> method for more information.
	/// </para>
	/// </remarks>
	/// <include file='examples.xml' path='//example[@id="RandomCharacters"][@type="images"]'/>
	/// <include file='examples.xml' path='//example[@id="RandomCharacters"][@type="config"]'/>
	/// <seealso cref="AutoInputProtection.DefaultTextProvider"/>
	/// <seealso cref="Configuration.AutoInputProtectionSection"/>
	/// <seealso cref="AutoInputProtectionImageProvider"/>
	/// <seealso cref="AutoInputProtectionFilterProvider"/>
	public sealed class RandomCharactersAutoInputProtectionTextProvider : AutoInputProtectionTextProvider
	{
		#region Public Properties
		/// <summary>
		/// Gets or sets the <see cref="CharacterSets"/> from which the provider will select individual characters 
		/// at random.
		/// </summary>
		/// <value>The valid <see cref="CharacterSets"/> for random text that is generated by the provider.</value>
		public CharacterSets IncludedCharacterSets
		{
			get
			{
				return includedCharacterSets;
			}
			set
			{
				includedCharacterSets = value;
			}
		}

		/// <summary>
		/// Gets or sets a string of characters that will never be used.
		/// </summary>
		/// <exception cref="ArgumentNullException">The specified value is <see langword="null"/>.</exception>
		/// <value>The characters that will never be used when random text is being generated.  The default value, set when 
		/// <see cref="Initialize"/> is called without specifying this property in the configuration, is: OoIiBQJj871lSs 
		/// (Oscar India Bravo Quebec Juliet Eight Seven One Lima Sierra).</value>
		public string ExcludedCharacters
		{
			get
			{
				return excludedCharacters;
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				excludedCharacters = value;
			}
		}
		#endregion

		#region Private / Protected
		private CharacterSets includedCharacterSets;
		private string excludedCharacters;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="RandomCharactersAutoInputProtectionTextProvider" /> class.
		/// </summary>
		public RandomCharactersAutoInputProtectionTextProvider()
		{
		}
		#endregion

		#region Methods
		/// <summary>
		/// Loads the provider's settings from the specified <paramref name="config"/>.
		/// </summary>
		/// <exception cref="ProviderException">A value could not be converted into the expected type.</exception>
		/// <param name="name">Name of the provider.</param>
		/// <param name="config">A collection of name and value pairs that will be used to initialize the provider.</param>
		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			if (config == null)
				throw new ArgumentNullException("config");

			if (String.IsNullOrEmpty(name))
				name = "RandomCharactersAutoInputProtectionTextProvider";

			if (string.IsNullOrEmpty(config["description"]))
			{
				config.Remove("description");
				config.Add("description", "Random Characters Auto-Input Protection Text Provider");
			}

			ProviderHelper helper = new ProviderHelper(config);

			includedCharacterSets = helper.ParseEnum<CharacterSets>("includedCharacterSets", false,
				CharacterSets.PositiveDigits | CharacterSets.UppercaseLetters);

			// Default: Oscar India Bravo Quebec Juliet Eight Seven One Lima Sierra
			excludedCharacters = config["excludedCharacters"] ?? "OoIiBQJj871lSs";

			base.Initialize(name, config);

			// Throw an exception if unrecognized attributes remain
			if (config.Count > 0)
			{
				string attr = config.GetKey(0);

				if (!String.IsNullOrEmpty(attr))
					throw new ProviderException(string.Format(System.Globalization.CultureInfo.CurrentUICulture,
						Errors.UnrecognizedAttribute, attr));
			}
		}

		/// <summary>
		/// Returns a string of random characters to be used as the text on an image that is generated by an 
		/// <see cref="AutoInputProtectionImage"/> implementation.
		/// </summary>
		/// <remarks>
		/// <see cref="RandomString.Create"/> is used to generate a string of random characters that are sampled from 
		/// <see cref="IncludedCharacterSets"/>, excluding the characters in <see cref="ExcludedCharacters"/>.  The number of 
		/// characters in the string is a random number between <see cref="AutoInputProtectionTextProvider.MinimumCharacters"/> and 
		/// <see cref="AutoInputProtectionTextProvider.MaximumCharacters"/>.
		/// </remarks>
		/// <returns>A string of random characters to be used as the text on an image for user validation.</returns>
		public override string GenerateRandomAutoInputProtectionText()
		{
			return RandomString.Create(MinimumCharacters, MaximumCharacters, includedCharacterSets, excludedCharacters);
		}
		#endregion
	}
}
